#pragma once

#include <cstdint>
#include <string>
#include <memory>
#include <map>
#include <set>
#include <mutex>
#include <iostream>

#include "r_socket_proxy/r_socket_proxy_def.h"

namespace eniac
{

enum class r_socket_status_t : uint8_t
{
    R_SOCKET_STATUS_STOPPING = 0,
    R_SOCKET_STATUS_STARTED
};

class r_socket
{
public:
    using ptr = std::shared_ptr<r_socket>;
    using id_t = std::int32_t;
    using fd_t = std::int32_t;
    using id_ptr_map = std::map<id_t, ptr>;
    using fd_ptr_map = std::map<fd_t, ptr>;
    using ptr_set = std::set<ptr>;

    r_socket() = default;
    r_socket(const r_socket& other) = delete;
    r_socket(r_socket&& other) = delete;
    r_socket& operator=(const r_socket& other) = delete;
    r_socket& operator=(r_socket&& other) = delete;
    ~r_socket() = default;

    static bool are_addresses_equal(r_socket::ptr l, r_socket::ptr r)
    {
        if (nullptr == l.get() ||
            nullptr == r.get() )
        {
            return false;
        }

        if ((l->m_own_address == r->m_own_address) &&
            (l->m_own_port == r->m_own_port)  )
        {
            return true;
        }
        return false;
    }

    r_socket_type       m_socket_type {r_socket_type::SOCKET_TYPE_UNKNOWN};
    id_t                m_socket_id {INVALID_SOCKET_ID};
    fd_t                m_socket_fd {INVALID_SOCKET_FD};
    id_t                m_host_id {INVALID_SOCKET_ID};
    std::set<id_t>      m_parnters {};
    std::string         m_own_address {""};
    std::uint16_t       m_own_port {INVALID_SOCKET_PORT};
    std::string         m_partner_address {""};
    std::uint16_t       m_partner_port {0};
    std::string         m_server_address {""};
    std::uint16_t       m_server_port {0};
    std::string         m_multicast_address {""};
    std::uint16_t       m_multicast_port {0};
    std::int32_t        m_max_listen_number {-1};
    r_socket_status_t   m_status {r_socket_status_t::R_SOCKET_STATUS_STOPPING};
    std::mutex m_mutex{};
};

}